from enum import Enum

KEYWORD_LOOKUP = [('SELECT', 1), ('FROM', 2), ('WHERE', 3), ('AS', 4), ('*', 5), 
                  ('INSERT', 6), ('INTO', 7), ('VALUES', 8), ('VALUE', 9), ('DEFAULT', 10),
                  ('UPDATE', 11), ('SET', 12), 
                  ('DELETE', 13),
                  ('JOIN', 14), ('LEFT', 15), ('RIGHT', 16), ('ON', 17),
                  ('MIN', 18), ('MAX', 19), ('AVG', 20), ('SUM', 21),
                  ('UNION', 22), ('ALL', 23),
                  ('GROUP', 24), ('HAVING', 25), ('DISTINCT', 26), ('ORDER', 27),
                  ('TRUE', 28), ('FALSE', 24), ('UNKNOWN', 30), ('IS', 31), ('NULL', 32)]
# 关键词对照字典

OP_LOOKUP = [('=', 1), ('>', 2), ('<', 3), ('>=', 4), ('<=', 5), ('!=', 6), ('<=>', 7),
             ('AND', 8), ('&&', 9), ('OR', 10), ('||', 11), ('XOR', 12), ('NOT', 13), ('!', 14),
             ('-', 15),
             ('.', 16)]
# 操作符对照字典

SE_LOOKUP = [('(', 1), (')', 2), (',', 3)]  # 界符对照字典


class COND(Enum):
    COND_WHITE = 1  # 空格
    COND_LETTER = 2  # 字母
    COND_NUMBER = 3  # 数字
    COND_SE = 4  # 界符
    COND_Lq = 5  # 引号
    COND_DASH = 6  # 减号
    COND_USCORE = 7  # 下划线
    COND_EQ = 16  # 等号
    COND_LESS = 8  # 小于
    COND_GREATER = 9  # 大于
    COND_NOT = 10  # 不等号
    COND_OR = 11  # 或
    COND_AND = 12  # 且
    COND_POINT = 13  # 点
    COND_OTHER = 14  # 其他
    COND_STAR = 15
    # 状态表


class STATE(Enum):
    S = 1  # 处态
    L1 = 2  # L1状态，表示由初态输入字母

    N1 = 3  # 处态输入数字
    N2 = 4  # N1输入小数点
    N3 = 5  # N2输入数字
    D1 = 6  # 处态输入负号
    ST1 = 14
    O1 = 7  # 处态输入小于号
    O2 = 8  # O1 输入等号
    O3 = 9  # 初态输入大于号
    O4 = 10  # 初态输入！
    O5 = 11  # 初态输入｜
    O6 = 12  # 初态输入 &

    Lq1 = 13  # 初态输入引号
    ERROR = -1  # 其他状态

    STOP_L1 = 101  # 结束态L1
    STOP_N1 = 102  # 结束态N1
    STOP_N2 = 103  # 结束态N1
    STOP_SE = 104  # 结束态SE
    STOP_O1 = 105  # 结束态O1
    STOP_O2 = 106  # 结束态O2
    STOP_O3 = 107  # 结束态3
    STOP_O4 = 108  # 结束态4
    STOP_O5 = 109  # 结束态5
    STOP_O6 = 110  # 结束态6
    STOP_O7 = 111  # 结束态7
    STOP_O8 = 112  # 结束态8
    STOP_O9 = 113  # 结束态9
    STOP_O10 = 114  # 结束态10
    STOP_Lq = 115  # 结束态Lq
    STOP_ST1 = 116
    STOP_O11 = 117

STOP_LIST = [
    STATE.STOP_L1,
    STATE.STOP_N1,
    STATE.STOP_N2,
    STATE.STOP_SE,
    STATE.STOP_O1,
    STATE.STOP_O2,
    STATE.STOP_O3,
    STATE.STOP_O4,
    STATE.STOP_O5,
    STATE.STOP_O6,
    STATE.STOP_O7,
    STATE.STOP_O8,
    STATE.STOP_O9,
    STATE.STOP_O10,
    STATE.STOP_Lq,
    STATE.STOP_ST1,
    STATE.STOP_O11
]  # 结束状态表

rollBackList = [
    STATE.STOP_L1,
    STATE.STOP_N1,
    STATE.STOP_N2,
    STATE.STOP_O2,
    STATE.STOP_O4,
    STATE.STOP_O5,
    STATE.STOP_ST1,
    STATE.STOP_O11
]

S_dict = {
    COND.COND_WHITE: STATE.S,
    COND.COND_LETTER: STATE.L1,
    COND.COND_NUMBER: STATE.N1,
    COND.COND_SE: STATE.STOP_SE,
    COND.COND_Lq: STATE.Lq1,
    COND.COND_DASH: STATE.D1,
    COND.COND_USCORE: STATE.L1,
    COND.COND_EQ: STATE.STOP_O1,
    COND.COND_LESS: STATE.O1,
    COND.COND_GREATER: STATE.O3,
    COND.COND_NOT: STATE.O4,
    COND.COND_OR: STATE.O5,
    COND.COND_AND: STATE.O6,
    COND.COND_POINT: STATE.STOP_O10,
    COND.COND_STAR: STATE.ST1,
}  # 初态可能转移到的下一个状态的字典

ST1_dict = {
    COND.COND_WHITE: STATE.STOP_ST1,
    COND.COND_LETTER: STATE.STOP_ST1,
}

L1_dict = {
    COND.COND_WHITE: STATE.STOP_L1,
    COND.COND_LETTER: STATE.L1,
    COND.COND_NUMBER: STATE.L1,
    COND.COND_USCORE: STATE.L1,
    COND.COND_POINT: STATE.STOP_L1,
    COND.COND_EQ: STATE.STOP_L1,
    COND.COND_LESS: STATE.STOP_L1,
    COND.COND_GREATER: STATE.STOP_L1,
    COND.COND_NOT: STATE.STOP_L1,
    COND.COND_OR: STATE.STOP_L1,
    COND.COND_AND: STATE.STOP_L1,
    COND.COND_SE: STATE.STOP_L1,
    COND.COND_STAR: STATE.STOP_L1,
}  # L1 可能转换到的下一个状态的字典


N1_dict = {
    COND.COND_WHITE: STATE.STOP_N2,
    COND.COND_NUMBER: STATE.N1,
    COND.COND_POINT: STATE.N2,
    COND.COND_EQ: STATE.STOP_N2,
    COND.COND_LESS: STATE.STOP_N2,
    COND.COND_GREATER: STATE.STOP_N2,
    COND.COND_NOT: STATE.STOP_N2,
    COND.COND_OR: STATE.STOP_N2,
    COND.COND_AND: STATE.STOP_N2,
    COND.COND_SE: STATE.STOP_N2
}  # N1 可能转换到的下一个状态的字典

N2_dict = {
    COND.COND_NUMBER: STATE.N3,
}  # N2 可能转换到的下一个状态的字典

N3_dict = {
    COND.COND_WHITE: STATE.STOP_N1,
    COND.COND_NUMBER: STATE.N3,
    COND.COND_EQ: STATE.STOP_N1,
    COND.COND_LESS: STATE.STOP_N1,
    COND.COND_GREATER: STATE.STOP_N1,
    COND.COND_NOT: STATE.STOP_N1,
    COND.COND_OR: STATE.STOP_N1,
    COND.COND_AND: STATE.STOP_N1,
    COND.COND_SE: STATE.STOP_N1
}  # N3 可能转换到的下一个状态的字典

D1_dcit = {
    COND.COND_NUMBER: STATE.N1
}  # D1 可能转换到的下一个状态的字典

O1_dict = {
    COND.COND_WHITE: STATE.STOP_O2,
    COND.COND_LETTER: STATE.STOP_O2,
    COND.COND_NUMBER: STATE.STOP_O2,
    COND.COND_SE: STATE.STOP_O2,
    COND.COND_Lq: STATE.STOP_O2,
    COND.COND_DASH: STATE.STOP_O2,
    COND.COND_USCORE: STATE.STOP_O2,
    COND.COND_EQ: STATE.O2,
    COND.COND_POINT: STATE.STOP_O2
}  # O1 可能转换到的下一个状态的字典

O2_dict = {
    COND.COND_WHITE: STATE.STOP_O4,
    COND.COND_LETTER: STATE.STOP_O4,
    COND.COND_NUMBER: STATE.STOP_O4,
    COND.COND_SE: STATE.STOP_O4,
    COND.COND_Lq: STATE.STOP_O4,
    COND.COND_DASH: STATE.STOP_O4,
    COND.COND_USCORE: STATE.STOP_O4,
    COND.COND_GREATER: STATE.STOP_O3,
    COND.COND_POINT: STATE.STOP_O4
}  # O2 可能转换到的下一个状态的字典

O3_dict = {
    COND.COND_WHITE: STATE.STOP_O5,
    COND.COND_LETTER: STATE.STOP_O5,
    COND.COND_NUMBER: STATE.STOP_O5,
    COND.COND_SE: STATE.STOP_O5,
    COND.COND_Lq: STATE.STOP_O5,
    COND.COND_DASH: STATE.STOP_O5,
    COND.COND_USCORE: STATE.STOP_O5,
    COND.COND_EQ: STATE.STOP_O6,
    COND.COND_POINT: STATE.STOP_O5,

}  # O3 可能转换到的下一个状态的字典

O4_dict = {
    COND.COND_WHITE: STATE.STOP_O11,
    COND.COND_LETTER: STATE.STOP_O11,
    COND.COND_NUMBER: STATE.STOP_O11,
    COND.COND_DASH: STATE.STOP_O11,
    COND.COND_USCORE: STATE.STOP_O11,
    COND.COND_EQ: STATE.STOP_O7
}  # O4 可能转换到的下一个状态的字典

O5_dict = {
    COND.COND_OR: STATE.STOP_O8
}  # O5 可能转换到的下一个状态的字典

O6_dict = {
    COND.COND_AND: STATE.STOP_O9
}  # O6 可能转换到的下一个状态的字典

Lq1_dict = {
    COND.COND_WHITE: STATE.Lq1,
    COND.COND_LETTER: STATE.Lq1,
    COND.COND_NUMBER: STATE.Lq1,
    COND.COND_SE: STATE.Lq1,
    COND.COND_Lq: STATE.STOP_Lq,
    COND.COND_DASH: STATE.Lq1,
    COND.COND_USCORE: STATE.Lq1,
    COND.COND_EQ: STATE.Lq1,
    COND.COND_LESS: STATE.Lq1,
    COND.COND_GREATER: STATE.Lq1,
    COND.COND_NOT: STATE.Lq1,
    COND.COND_OR: STATE.Lq1,
    COND.COND_AND: STATE.Lq1,
    COND.COND_POINT: STATE.Lq1,
    COND.COND_OTHER: STATE.Lq1,
    COND.COND_STAR: STATE.Lq1
}
# 左引号后可能的状态，由于是字符串，因此除了引号以外，状态不变

stateTbale = {
    STATE.S: S_dict,
    STATE.L1: L1_dict,
    STATE.N1: N1_dict,
    STATE.N2: N2_dict,
    STATE.N3: N3_dict,
    STATE.D1: D1_dcit,
    STATE.O1: O1_dict,
    STATE.O2: O2_dict,
    STATE.O3: O3_dict,
    STATE.O4: O4_dict,
    STATE.O5: O5_dict,
    STATE.O6: O6_dict,
    STATE.Lq1: Lq1_dict,
    STATE.ST1: ST1_dict
}  # 非终结状态对应表


def isKeyWord(lexeme: str):  # 寻找是否是关键词，如果是关键词，则返回关键词序号
    for elm in KEYWORD_LOOKUP:
        if (elm[0] == lexeme):
            return elm[1]
    return False


def isOP(lexeme: str):  # 寻找是否是操作符，如果是操作符，则返回操作符序号
    for elm in OP_LOOKUP:
        if (elm[0] == lexeme):
            return elm[1]
    return False


def isSE(lexeme: str):  # 寻找是否是界符，如果是界符，则返回界符序号
    for elm in SE_LOOKUP:
        if (elm[0] == lexeme):
            return elm[1]
    assert (1)


def isIDN(lexeme: str):
    for index in range(0, len(lexeme)):
        char = lexeme[index]
        if not (char.isalpha or char.isnumeric or char == '_'):
            return False  # 一串字符中出现除了数字，字符，下划线以外的字符，返回false
        if index == 0 and char.isnumeric():
            return False  # 如果出现以数字为开头的字符串，返回fa import os.path as osp
    return True


def getCond(c: str):  # 获取状态
    if c == ' ':
        return COND.COND_WHITE
    elif c.isalpha():
        return COND.COND_LETTER
    elif c.isnumeric():
        return COND.COND_NUMBER
    elif isSE(c):
        return COND.COND_SE
    elif c == '"' or c == "'":
        return COND.COND_Lq
    elif c == '-':
        return COND.COND_DASH
    elif c == '_':
        return COND.COND_USCORE
    elif c == '=':
        return COND.COND_EQ
    elif c == '<':
        return COND.COND_LESS
    elif c == '>':
        return COND.COND_GREATER
    elif c == '!':
        return COND.COND_NOT
    elif c == '|':
        return COND.COND_OR
    elif c == '&':
        return COND.COND_AND
    elif c == '.':
        return COND.COND_POINT
    elif c == '*':
        return COND.COND_STAR
    else:
        return COND.COND_OTHER

def getToken(state: STATE, value: str, SQLstring: str):
    assert (state in STOP_LIST)
    value = value.upper()
    if state is STATE.STOP_L1:
        if isKeyWord(value):
            if value == 'GROUP' or value == 'ORDER':
                if SQLstring[0:4] == ' BY ':
                    return ('KW' , isKeyWord(value) ), 3
                else:
                    print("syntax error at GROUP BY / ORDER BY")
                    assert(False)
            else:
                return ('KW', isKeyWord(value)), 0
        elif isOP(value):
            return ('OP', isOP(value), ), 0
        elif isIDN(value):
            return ('IDN', value), 0
        else:
            assert (False)
    if state is STATE.STOP_ST1:
        return ('KW', isKeyWord(value)), 0

    if state is STATE.STOP_N1:
        return ('FLOAT', value), 0

    if state is STATE.STOP_N2:
        return ('INT', value), 0

    if state is STATE.STOP_SE:
        return ('SE', isSE(value)), 0

    if state is STATE.STOP_O1:
        return ('OP',isOP(value)), 0

    if state is STATE.STOP_O2:
        return ('OP',isOP(value)), 0

    if state is STATE.STOP_O3:
        return ('OP',isOP(value)), 0

    if state is STATE.STOP_O4:
        return ('OP',isOP(value)), 0

    if state is STATE.STOP_O5:
        return ('OP',isOP(value)), 0

    if state is STATE.STOP_O6:
        return ('OP',isOP(value)), 0

    if state is STATE.STOP_O7:
        return ('OP',isOP(value)), 0

    if state is STATE.STOP_O8:
        return ('OP', isOP(value)), 0

    if state is STATE.STOP_O9:
        return ('OP',isOP(value)), 0

    if state is STATE.STOP_O10:
        return ('OP', isOP(value)), 0

    if state is STATE.STOP_Lq:
        return ('STRING', value), 0

    if state is STATE.STOP_O11:
        return ('OP', isOP(value)), 0
    assert (False)
